import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime, timedelta
import warnings
warnings.filterwarnings('ignore')

# 导入自定义模块
from sales_prediction_models import *
from sales_prediction_pipeline import *

class SalesPredictionSystem:
    """手机配件销售预测系统主类"""
    
    def __init__(self):
        self.pipeline = SalesPredictionPipeline()
        self.preprocessor = DataPreprocessor()
        self.results = {}
        self.historical_stats = {}
        
    def load_and_preprocess_data(self, train_file='1.xlsx', pred_file='2.xlsx'):
        """加载和预处理数据"""
        print("=== 数据加载和预处理 ===")
        
        # 1. 加载训练数据
        print(f"加载训练数据: {train_file}")
        df_train = pd.read_excel(train_file)
        print(f"训练数据形状: {df_train.shape}")
        print(f"空值统计: {df_train.isnull().sum().to_dict()}")
        
        # 2. 加载预测数据
        print(f"\n加载预测数据: {pred_file}")
        df_pred = pd.read_excel(pred_file)
        print(f"预测数据形状: {df_pred.shape}")
        
        # 3. 预处理训练数据
        print("\n预处理训练数据...")
        X_train, y_train, df_train_processed = self.preprocessor.prepare_features(
            df_train, date_col='finish_time', target_col='value'
        )
        
        # 4. 预处理预测数据
        print("预处理预测数据...")
        X_pred, _, df_pred_processed = self.preprocessor.prepare_features(
            df_pred, date_col='finish_time', target_col=None
        )
        
        # 保存历史数据统计信息
        self.historical_stats = {
            'mean_sales': y_train.mean(),
            'std_sales': y_train.std(),
            'zero_ratio': (y_train == 0).mean(),
            'non_zero_mean': y_train[y_train > 0].mean() if (y_train > 0).any() else 0
        }
        
        print(f"历史数据统计:")
        print(f"  平均销售额: {self.historical_stats['mean_sales']:.2f}")
        print(f"  销售额标准差: {self.historical_stats['std_sales']:.2f}")
        print(f"  零销售比例: {self.historical_stats['zero_ratio']:.2%}")
        print(f"  非零销售均值: {self.historical_stats['non_zero_mean']:.2f}")
        
        return X_train, y_train, X_pred, df_train_processed, df_pred_processed
    
    def initialize_models(self):
        """初始化所有预测模型"""
        print("\n=== 初始化预测模型 ===")
        
        # 添加各种预测模型
        models = {
            'LinearRegression': LinearRegressionPredictor(),
            'RidgeRegression': RidgeRegressionPredictor(alpha=1.0),
            'RandomForest': RandomForestPredictor(n_estimators=100),
            'GradientBoosting': GradientBoostingPredictor(n_estimators=100),
            'TimeSeries': TimeSeriesPredictor(window=7)
        }
        
        for model_name, model in models.items():
            self.pipeline.add_model(model_name, model)
            print(f"  添加模型: {model_name}")
        
        print(f"总共初始化了 {len(models)} 个模型")
    
    def train_models(self, X_train, y_train):
        """训练所有模型"""
        print("\n=== 训练模型 ===")
        
        training_results = self.pipeline.train_all_models(X_train, y_train)
        
        print("训练结果:")
        for model_name, result in training_results.items():
            status = "✓" if result == "成功" else "✗"
            print(f"  {status} {model_name}: {result}")
        
        return training_results
    
    def make_predictions(self, X_pred):
        """使用所有模型进行预测"""
        print("\n=== 进行预测 ===")
        
        # 获取所有模型的预测结果
        all_predictions = self.pipeline.predict_with_all_models(X_pred)
        
        print(f"获得 {len(all_predictions)} 个模型的预测结果")
        for model_name, predictions in all_predictions.items():
            print(f"  {model_name}: 预测均值={np.mean(predictions):.2f}, 范围=[{np.min(predictions):.2f}, {np.max(predictions):.2f}]")
        
        return all_predictions
    
    def ensemble_predictions(self, all_predictions):
        """整合预测结果"""
        print("\n=== 整合预测结果 ===")
        
        # 执行集成预测
        ensemble_pred = self.pipeline.run_ensemble_prediction(all_predictions, method='weighted_average')
        
        print(f"集成预测结果: 均值={np.mean(ensemble_pred):.2f}, 范围=[{np.min(ensemble_pred):.2f}, {np.max(ensemble_pred):.2f}]")
        
        return ensemble_pred
    
    def post_process_predictions(self, predictions, dates=None):
        """后处理预测结果"""
        print("\n=== 后处理预测结果 ===")
        
        # 设置后处理规则
        post_processing_rules = {
            'min_value': 0,
            'max_value': self.historical_stats['mean_sales'] * 3,  # 不超过历史均值的3倍
            'integer': True,
            'smooth': True,
            'outlier_handle': True
        }
        
        self.pipeline.post_processor.set_processing_rules(post_processing_rules)
        
        # 应用后处理
        processed_predictions = self.pipeline.post_processor.post_process(
            predictions, historical_data=None
        )
        
        # 应用业务规则
        if dates is not None:
            processed_predictions = self.pipeline.post_processor.apply_business_rules(
                processed_predictions, dates
            )
        
        print(f"后处理前: 均值={np.mean(predictions):.2f}")
        print(f"后处理后: 均值={np.mean(processed_predictions):.2f}")
        
        return processed_predictions
    
    def evaluate_predictions(self, y_true=None, y_pred=None):
        """评估预测结果（如果有真实值）"""
        if y_true is not None and y_pred is not None:
            print("\n=== 评估预测结果 ===")
            
            metrics = self.pipeline.evaluator.calculate_metrics(y_true, y_pred)
            self.pipeline.evaluator.print_evaluation_report()
            
            return metrics
        else:
            print("\n=== 无法评估（没有真实值） ===")
            return None
    
    def save_results(self, predictions, dates, output_file='3.xlsx', include_all_models=True):
        """保存预测结果"""
        print(f"\n=== 保存结果到 {output_file} ===")
        
        # 创建结果DataFrame
        results_df = pd.DataFrame({
            'finish_time': dates,
            'predicted_sales': predictions
        })
        
        # 如果包含所有模型的预测结果
        if include_all_models and hasattr(self, 'all_predictions'):
            for model_name, pred in self.all_predictions.items():
                results_df[f'pred_{model_name}'] = pred
        
        # 添加统计信息
        results_df['prediction_confidence'] = 'medium'  # 可以根据模型方差等计算
        
        # 保存到Excel
        results_df.to_excel(output_file, index=False)
        
        print(f"结果已保存到 {output_file}")
        print(f"预测记录数: {len(results_df)}")
        print(f"预测时间范围: {results_df['finish_time'].min()} 到 {results_df['finish_time'].max()}")
        
        return results_df
    
    def generate_report(self, all_predictions, ensemble_pred, final_pred):
        """生成预测报告"""
        print("\n=== 预测报告 ===")
        
        # 模型预测统计
        print("各模型预测统计:")
        for model_name, predictions in all_predictions.items():
            stats = {
                'mean': np.mean(predictions),
                'std': np.std(predictions),
                'min': np.min(predictions),
                'max': np.max(predictions)
            }
            print(f"  {model_name}:")
            print(f"    均值: {stats['mean']:.2f}, 标准差: {stats['std']:.2f}")
            print(f"    范围: [{stats['min']:.2f}, {stats['max']:.2f}]")
        
        # 集成预测统计
        ensemble_stats = {
            'mean': np.mean(ensemble_pred),
            'std': np.std(ensemble_pred),
            'min': np.min(ensemble_pred),
            'max': np.max(ensemble_pred)
        }
        
        print(f"\n集成预测统计:")
        print(f"  均值: {ensemble_stats['mean']:.2f}, 标准差: {ensemble_stats['std']:.2f}")
        print(f"  范围: [{ensemble_stats['min']:.2f}, {ensemble_stats['max']:.2f}]")
        
        # 最终预测统计
        final_stats = {
            'mean': np.mean(final_pred),
            'std': np.std(final_pred),
            'min': np.min(final_pred),
            'max': np.max(final_pred)
        }
        
        print(f"\n最终预测统计:")
        print(f"  均值: {final_stats['mean']:.2f}, 标准差: {final_stats['std']:.2f}")
        print(f"  范围: [{final_stats['min']:.2f}, {final_stats['max']:.2f}]")
        
        # 零销售预测比例
        zero_ratio = (np.array(final_pred) == 0).mean()
        print(f"\n零销售预测比例: {zero_ratio:.2%}")
        
        return {
            'model_predictions': all_predictions,
            'ensemble_prediction': ensemble_pred,
            'final_prediction': final_pred,
            'statistics': {
                'ensemble': ensemble_stats,
                'final': final_stats
            }
        }
    
    def run_complete_pipeline(self, train_file='1.xlsx', pred_file='2.xlsx', output_file='3.xlsx'):
        """运行完整的预测流程"""
        print("=== 手机配件销售预测系统 ===")
        print(f"开始时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        
        try:
            # 1. 数据加载和预处理
            print("开始数据加载和预处理...")
            X_train, y_train, X_pred, df_train, df_pred = self.load_and_preprocess_data(train_file, pred_file)
            
            if X_train is None or y_train is None or X_pred is None:
                raise ValueError("数据预处理失败")
            
            # 2. 初始化模型
            print("开始初始化模型...")
            self.initialize_models()
            
            # 3. 训练模型
            print("开始训练模型...")
            training_results = self.train_models(X_train, y_train)
            
            # 4. 进行预测
            print("开始进行预测...")
            all_predictions = self.make_predictions(X_pred)
            self.all_predictions = all_predictions  # 保存供后续使用
            
            # 5. 整合预测结果
            print("开始整合预测结果...")
            ensemble_pred = self.ensemble_predictions(all_predictions)
            
            # 6. 后处理
            print("开始后处理...")
            pred_dates = df_pred['finish_time']
            final_pred = self.post_process_predictions(ensemble_pred, dates=pred_dates)
            
            # 7. 保存结果
            print("开始保存结果...")
            results_df = self.save_results(final_pred, pred_dates, output_file)
            
            # 8. 生成报告
            print("开始生成报告...")
            report = self.generate_report(all_predictions, ensemble_pred, final_pred)
            
            print(f"\n=== 流程完成 ===")
            print(f"结束时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
            
            return {
                'status': 'success',
                'results_df': results_df,
                'report': report,
                'training_results': training_results
            }
            
        except Exception as e:
            print(f"\n流程执行失败: {e}")
            import traceback
            traceback.print_exc()
            return {
                'status': 'error',
                'error': str(e)
            }

if __name__ == "__main__":
    # 创建预测系统实例
    prediction_system = SalesPredictionSystem()
    
    # 运行完整流程
    result = prediction_system.run_complete_pipeline()
    
    if result['status'] == 'success':
        print("\n✓ 销售预测系统运行成功！")
    else:
        print(f"\n✗ 系统运行失败: {result['error']}")